home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / edit / jed207.lha / src / jed.lha / scriptcmds.c < prev    next >
C/C++ Source or Header  |  1993-01-06  |  17KB  |  826 lines

  1.  
  2. /*
  3.  * SCRIPTCMDS.C
  4.  * (c) 1992-3 J.Harper
  5.  */
  6.  
  7. #include "jed.h"
  8. #include "jed_protos.h"
  9.  
  10. Prototype   VALUE *    cmd_script    (LONG, VALUE *);
  11. Prototype   VALUE *    cmd_nargs    (LONG, VALUE *);
  12. Prototype   VALUE *    cmd_arg        (LONG, VALUE *);
  13. Prototype   VALUE *    cmd_if        (LONG, VALUE *);
  14. Prototype   VALUE *    cmd_while    (LONG, VALUE *);
  15. Prototype   VALUE *    cmd_select    (LONG, VALUE *);
  16. Prototype   VALUE *    cmd_dowhile    (LONG, VALUE *);
  17. Prototype   VALUE *    cmd_return    (LONG, VALUE *);
  18. Prototype   VALUE *    cmd_break    (LONG, VALUE *);
  19. Prototype   VALUE *    cmd_addsym    (LONG, VALUE *);
  20. Prototype   VALUE *    cmd_remsym    (LONG, VALUE *);
  21. Prototype   VALUE *    cmd_renamesym    (LONG, VALUE *);
  22. Prototype   VALUE *    cmd_export    (LONG, VALUE *);
  23. Prototype   VALUE *    cmd_type    (LONG, VALUE *);
  24. Prototype   VALUE *    cmd_plus    (LONG, VALUE *);
  25. Prototype   VALUE *    cmd_minus    (LONG, VALUE *);
  26. Prototype   VALUE *    cmd_product    (LONG, VALUE *);
  27. Prototype   VALUE *    cmd_divide    (LONG, VALUE *);
  28. Prototype   VALUE *    cmd_mod        (LONG, VALUE *);
  29. Prototype   VALUE *    cmd_b_not    (LONG, VALUE *);
  30. Prototype   VALUE *    cmd_l_not    (LONG, VALUE *);
  31. Prototype   VALUE *    cmd_b_or    (LONG, VALUE *);
  32. Prototype   VALUE *    cmd_l_or    (LONG, VALUE *);
  33. Prototype   VALUE *    cmd_b_and    (LONG, VALUE *);
  34. Prototype   VALUE *    cmd_l_and    (LONG, VALUE *);
  35. Prototype   VALUE *    cmd_b_eor    (LONG, VALUE *);
  36. Prototype   VALUE *    cmd_l_eor    (LONG, VALUE *);
  37. Prototype   VALUE *    cmd_lshift    (LONG, VALUE *);
  38. Prototype   VALUE *    cmd_rshift    (LONG, VALUE *);
  39. Prototype   VALUE *    cmd_equals    (LONG, VALUE *);
  40. Prototype   VALUE *    cmd_equality    (LONG, VALUE *);
  41. Prototype   VALUE *    cmd_inequality    (LONG, VALUE *);
  42. Prototype   VALUE *    cmd_gtthan    (LONG, VALUE *);
  43. Prototype   VALUE *    cmd_ltthan    (LONG, VALUE *);
  44. Prototype   VALUE *    cmd_gethan    (LONG, VALUE *);
  45. Prototype   VALUE *    cmd_lethan    (LONG, VALUE *);
  46. Prototype   VALUE *    cmd_nop        (LONG, VALUE *);
  47.  
  48. /*
  49.  * (script `sectType')
  50.  * (script `x' `file')  - x stands for external (f is a section type)
  51.  */
  52. VALUE *
  53. cmd_script(LONG argc, VALUE *argv)
  54. {
  55.     if(TPLATE2(VTF_STRING, VTF_ANY))
  56.     {
  57.     if(*(ARG1.val_Value.String) == 'x')
  58.     {
  59.         if(ARG2.val_Type == VTF_STRING)
  60.         {
  61.         STRPTR file;
  62.         if(!(file = squirrelfile(ARG2.val_Value.String)))
  63.         {
  64.             UBYTE othername[200];
  65.             strcpy(othername, "s:jed/");
  66.             AddPart(othername, ARG2.val_Value.String, 200);
  67.             file = squirrelfile(othername);
  68.         }
  69.         if(file)
  70.         {
  71.             if(!execstr(file, &RES, FALSE, 0, NULL))
  72.             {
  73.             freestring(file);
  74.             return(FALSE);
  75.             }
  76.             freestring(file);
  77.         }
  78.         else
  79.             doserror();
  80.         }
  81.         else
  82.         settitle("syntax error: argument 2 should be a string.");
  83.     }
  84.     else if(*(ARG1.val_Value.String) == 's')
  85.     {
  86.         if(ARG2.val_Type == VTF_STRING)
  87.         {
  88.         if(!execstr(ARG2.val_Value.String, &RES, FALSE, 0, NULL))
  89.             return(FALSE);
  90.         }
  91.         else
  92.         settitle("syntax error: argument 2 should be a string.");
  93.     }
  94.     else
  95.     {
  96.         POS temp = CurrVW->vw_CursorPos;
  97.         POS endpos;
  98.         if(getsection(ARG1.val_Value.String, &endpos))
  99.         {
  100.         POS startpos = CurrVW->vw_CursorPos;
  101.         LONG length;
  102.         STRPTR text;
  103.         CurrVW->vw_CursorPos = temp;
  104.         length = sectionlength(&startpos, &endpos);
  105.         if(text = AllocVec(length + 1, 0L))
  106.         {
  107.             copysection(&startpos, &endpos, text);
  108.             text[length] = 0;
  109.             if(!execstr(text, &RES, FALSE, 0, NULL))
  110.             {
  111.             FreeVec(text);
  112.             return(FALSE);
  113.             }
  114.             FreeVec(text);
  115.         }
  116.         else
  117.             settitle(NoMemMsg);
  118.         }
  119.     }
  120.     }
  121.     return(&RES);
  122. }
  123.  
  124. /*
  125.  * returns the number of arguments passed to the innermost macro
  126.  * (nargs)
  127.  */
  128. VALUE *
  129. cmd_nargs(LONG argc, VALUE *argv)
  130. {
  131.     LONG xargc;
  132.     VALUE *xargv;
  133.     if(findsargs(&xargc, &xargv))
  134.     {
  135.     setnumres(xargc);
  136.     }
  137.     return(&RES);
  138. }
  139.  
  140. /*
  141.  * returns an argument (prompts for it if it wasn't given)
  142.  * (arg n `type' [`prompt'])
  143.  *
  144.  * type defines the type of value required -- `s' = string, `n' = number.
  145.  * `e' = either
  146.  * if an argument of the proper type can't be got then the macro is
  147.  * aborted.
  148.  */
  149. VALUE *
  150. cmd_arg(LONG argc, VALUE *argv)
  151. {
  152.     VALUE *res = &RES;
  153.     if(TPLATE2(VTF_NUMBER, VTF_STRING))
  154.     {
  155.     LONG xargc;
  156.     VALUE *xargv;
  157.     if(findsargs(&xargc, &xargv))
  158.     {
  159.         LONG argnum = ARG1.val_Value.Number;
  160.         switch(*(ARG2.val_Value.String))
  161.         {
  162.         case 'e':
  163.             dupvalue(&RES, &xargv[argnum]);
  164.             break;
  165.         case 's':
  166.             STRPTR arg = NULL;
  167.             if(xargv[argnum].val_Type == VTF_STRING)
  168.             dupvalue(&RES, &xargv[argnum]);
  169.             else
  170.             {
  171.             if(ARG3.val_Type == VTF_STRING)
  172.                 arg = docmdline(ARG3.val_Value.String);
  173.             else
  174.                 arg = docmdline("string> ");
  175.             if(argc)
  176.             {
  177.                 setstrres(arg);
  178.             }
  179.             }
  180.             break;
  181.         case 'n':
  182.             STRPTR str;
  183.             if(xargv[argnum].val_Type == VTF_NUMBER)
  184.             dupvalue(&RES, &xargv[argnum]);
  185.             else
  186.             {
  187.             if(ARG3.val_Type == VTF_STRING)
  188.                 str = docmdline(ARG3.val_Value.String);
  189.             else
  190.                 str = docmdline("number> ");
  191.             if(str)
  192.             {
  193.                 if(isdigit(*str) || (*str == '-'))
  194.                 {
  195.                 APTR dummy;
  196.                 setnumres(strtol(str, &dummy, 0));
  197.                 }
  198.                 freestring(str);
  199.             }
  200.             }
  201.             break;
  202.         }
  203.         if(RES.val_Type == VTF_NONE)
  204.         {
  205.         settitlefmt("syntax error: no arg %ld provided", ARG1.val_Value.Number);
  206.         res = FALSE;
  207.         }
  208.     }
  209.     else
  210.     {
  211.         settitle("error: not in macro - can't use arg command");
  212.         res = FALSE;
  213.     }
  214.     }
  215.     else
  216.     res = FALSE;
  217.     return(res);
  218. }
  219.  
  220. /*
  221.  * (if condition-clause `true-clause' `false-clause')
  222.  *
  223.  * result is value of evaluated clause.
  224.  */
  225. VALUE *
  226. cmd_if(LONG argc, VALUE *argv)
  227. {
  228.     if(TPLATE3(VTF_NUMBER, VTF_ANY, VTF_ANY))
  229.     {
  230.     if(ARG1.val_Value.Number)
  231.     {
  232.         if(ARG2.val_Type == VTF_STRING)
  233.         {
  234.         if(!execstr(ARG2.val_Value.String, &RES, FALSE, 0, NULL))
  235.             return(FALSE);
  236.         }
  237.     }
  238.     else
  239.     {
  240.         if(ARG3.val_Type == VTF_STRING)
  241.         {
  242.         if(!execstr(ARG3.val_Value.String, &RES, FALSE, 0, NULL))
  243.             return(FALSE);
  244.         }
  245.     }
  246.     }
  247.     return(&RES);
  248. }
  249.  
  250. /*
  251.  * (while `condition-clause' `true-clause')
  252.  *
  253.  * result is number of iterations before stopping.
  254.  * loop will be broken after MAX_ITS number of iterations or a ^C break
  255.  * signal is received.
  256.  */
  257. #define MAX_ITS (1000000)
  258.  
  259. VALUE *
  260. cmd_while(LONG argc, VALUE *argv)
  261. {
  262.     if(TPLATE2(VTF_STRING, VTF_STRING))
  263.     {
  264.     LONG i;
  265.     for(i = 0; i < MAX_ITS; i++)
  266.     {
  267.         VALUE value;
  268.         if(!execstr(ARG1.val_Value.String, &value, FALSE, 0, NULL))
  269.         {
  270.         releasevalue(&value);
  271.         return(FALSE);
  272.         }
  273.         if(!value.val_Value.Number)
  274.         {
  275.         releasevalue(&value);
  276.         setnumres(i);
  277.         return(&RES);
  278.         }
  279.         releasevalue(&value);
  280.         if(!execstr(ARG2.val_Value.String, &value, FALSE, 0, NULL))
  281.         {
  282.         releasevalue(&value);
  283.         return(FALSE);
  284.         }
  285.         releasevalue(&value);
  286.         if(CheckSignal(SIGBREAKF_CTRL_C))
  287.         {
  288.         settitle("^C: while aborted");
  289.         break;
  290.         }
  291.     }
  292.     if(i == MAX_ITS)
  293.         settitle("wow... a million iterations, while loop aborted");
  294.     }
  295.     return(FALSE);
  296. }
  297.  
  298. /*
  299.  *  (select
  300.  *    (cond1)
  301.  *        `reaction1'
  302.  *    (cond2)
  303.  *        `reaction2'
  304.  *    ...
  305.  *    `default'
  306.  *  )
  307.  */
  308. VALUE *
  309. cmd_select(LONG argc, VALUE *argv)
  310. {
  311.     VALUE *res;
  312.     WORD i;
  313.     for(i = 0; i < argc; i += 2)
  314.     {
  315.     if((argv[i + 1].val_Type == VTF_NUMBER) && (argv[i + 2].val_Type == VTF_STRING))
  316.     {
  317.         if(argv[i + 1].val_Value.Number)
  318.         return(execstr(argv[i + 2].val_Value.String, &RES, FALSE, 0, NULL));
  319.     }
  320.     else if(argv[i + 1].val_Type == VTF_STRING)
  321.         return(execstr(argv[i + 1].val_Value.String, &RES, FALSE, 0, NULL));
  322.     }
  323.     return(&RES);
  324. }
  325.  
  326. /*
  327.  * (dowhile `command' `condition')
  328.  *
  329.  * similar to a C 'do...while' loop.
  330.  */
  331. VALUE *
  332. cmd_dowhile(LONG argc, VALUE *argv)
  333. {
  334.     if(TPLATE2(VTF_STRING, VTF_STRING))
  335.     {
  336.     LONG i;
  337.     for(i = 0; i < MAX_ITS; i++)
  338.     {
  339.         VALUE value;
  340.         if(!execstr(ARG1.val_Value.String, &value, FALSE, 0, NULL))
  341.         {
  342.         releasevalue(&value);
  343.         return(FALSE);
  344.         }
  345.         releasevalue(&value);
  346.         if(!execstr(ARG2.val_Value.String, &value, FALSE, 0, NULL))
  347.         {
  348.         releasevalue(&value);
  349.         return(FALSE);
  350.         }
  351.         if(!value.val_Value.Number)
  352.         {
  353.         releasevalue(&value);
  354.         setnumres(i);
  355.         return(&RES);
  356.         }
  357.         if(CheckSignal(SIGBREAKF_CTRL_C))
  358.         {
  359.         settitle("^C: dowhile aborted");
  360.         break;
  361.         }
  362.     }
  363.     if(i == MAX_ITS)
  364.         settitle("wow... a million iterations, dowhile loop aborted");
  365.     }
  366.     return(FALSE);
  367. }
  368.  
  369. /*
  370.  * breaks from the macro, returns ARG1
  371.  */
  372. VALUE *
  373. cmd_return(LONG argc, VALUE *argv)
  374. {
  375.     dupvalue(&RES, &ARG1);
  376.     return(FALSE);
  377. }
  378.  
  379. /*
  380.  * (break n)
  381.  * Breaks out of n depths of strings that are currently being executed.
  382.  */
  383. VALUE *
  384. cmd_break(LONG argc, VALUE *argv)
  385. {
  386.     RES.val_Type = VTF_BREAK;
  387.     if(ARG1.val_Type == VTF_NUMBER)
  388.     {
  389.     if((RES.val_Value.Number = ARG1.val_Value.Number) <= 0)
  390.     {
  391.         RES.val_Type = VTF_NONE;
  392.         return(&RES);
  393.     }
  394.     }
  395.     else
  396.     RES.val_Value.Number = 1;
  397.     return(FALSE);
  398. }
  399.  
  400. /*
  401.  * (addsym {`sym-name' value symbol-type})
  402.  *
  403.  * symbol-type is,
  404.  *  1 -- global command
  405.  *  2 -- global variable
  406.  *  3 -- local command
  407.  *  4 -- local variable
  408.  */
  409. VALUE *
  410. cmd_addsym(LONG argc, VALUE *argv)
  411. {
  412.     VALUE *res = &RES;
  413.     BOOL rc = TRUE;
  414.     while(rc && (argc >= 3))
  415.     {
  416.     if(TPLATE3(VTF_STRING, VTF_ANY, VTF_NUMBER))
  417.     {
  418.         if(ARG3.val_Value.Number <= 2)
  419.         {
  420.         if(!addgsym(ARG1.val_Value.String, ARG3.val_Value.Number, &ARG2))
  421.             rc = FALSE;
  422.         }
  423.         else
  424.         {
  425.         if(!addlsym(ARG1.val_Value.String, ARG3.val_Value.Number - 2, &ARG2))
  426.             rc = FALSE;
  427.         }
  428.         if(!rc)
  429.         settitlefmt("error: can't create variable %s", (LONG)ARG1.val_Value.String);
  430.     }
  431.     else
  432.         goto abort;
  433.     argc -= 3;
  434.     argv += 3;
  435.     }
  436.     res->val_Type = VTF_NUMBER;
  437.     res->val_Value.Number = rc;
  438. abort:
  439.     return(res);
  440. }
  441.  
  442. /*
  443.  * (remsym {`sym-name'})
  444.  *
  445.  * note that if you want you can remove the primitive commands!
  446.  */
  447. VALUE *
  448. cmd_remsym(LONG argc, VALUE *argv)
  449. {
  450.     VALUE *res = &RES;
  451.     BOOL rc = TRUE;
  452.     while(rc && (argc >= 1))
  453.     {
  454.     if(TPLATE1(VTF_STRING))
  455.     {
  456.         if(!remsym(ARG1.val_Value.String))
  457.         {
  458.         settitlefmt("error: can't remove symbol %s", (LONG)ARG1.val_Value.String);
  459.         rc = FALSE;
  460.         }
  461.     }
  462.     else
  463.         goto abort;
  464.     argc--;
  465.     argv++;
  466.     }
  467.     res->val_Type = VTF_NUMBER;
  468.     res->val_Value.Number = rc;
  469. abort:
  470.     return(res);
  471. }
  472.  
  473. /*
  474.  * (renamesym {`old-name' `new-name'})
  475.  *
  476.  * This can be used to rename primitive commands so that a macro can sit
  477.  * on top of it.
  478.  */
  479. VALUE *
  480. cmd_renamesym(LONG argc, VALUE *argv)
  481. {
  482.     VALUE *res = &RES;
  483.     BOOL rc = TRUE;
  484.     while(rc && (argc >= 2))
  485.     {
  486.     if(TPLATE2(VTF_STRING, VTF_STRING))
  487.     {
  488.         GSYM *sym;
  489.         if(sym = findgsym(ARG1.val_Value.String))
  490.         {
  491.         STRPTR newname;
  492.         if(newname = savestring(ARG2.val_Value.String))
  493.         {
  494.             removehash(SymbolTab, &sym->gs_Node, GSYMTABSIZE);
  495.             freestring(sym->gs_Node.h_Name);
  496.             sym->gs_Node.h_Name = newname;
  497.             inserthash(SymbolTab, &sym->gs_Node, GSYMTABSIZE);
  498.         }
  499.         else
  500.         {
  501.             settitle(NoMemMsg);
  502.             rc = FALSE;
  503.         }
  504.         }
  505.         else
  506.         {
  507.         settitlefmt("error: no symbol %s", (LONG)ARG1.val_Value.String);
  508.         rc = FALSE;
  509.         }
  510.     }
  511.     else
  512.         goto abort;
  513.     argc -= 2;
  514.     argv += 2;
  515.     }
  516.     res->val_Type = VTF_NUMBER;
  517.     res->val_Value.Number = rc;
  518. abort:
  519.     return(res);
  520. }
  521.  
  522. /*
  523.  * (export {`lsym' how-far})
  524.  *
  525.  * moves lsym from its current depth to (current_depth - how_far)
  526.  */
  527. VALUE *
  528. cmd_export(LONG argc, VALUE *argv)
  529. {
  530.     VALUE *res = &RES;
  531.     BOOL rc = TRUE;
  532.     while(rc && (argc >= 2))
  533.     {
  534.     if(TPLATE2(VTF_STRING, VTF_NUMBER))
  535.     {
  536.         LSYM *ls = NULL;
  537.         WORD i;
  538.         for(i = CSDepth; !ls && i; i--)
  539.         {
  540.         for(ls = (LSYM *)CSList[i].cs_Locals.lh_Head; ls->ls_Node.ln_Succ; ls = (LSYM *)ls->ls_Node.ln_Succ)
  541.         {
  542.             if(!strcmp(ARG1.val_Value.String, ls->ls_Node.ln_Name))
  543.             break;
  544.         }
  545.         }
  546.         i -= ARG2.val_Value.Number;
  547.         if(ls && (i > 0))
  548.         {
  549.         Remove(&ls->ls_Node);
  550.         AddTail(&CSList[i].cs_Locals, &ls->ls_Node);
  551.         }
  552.         else
  553.         {
  554.         settitlefmt("error: no local symbol %s", (LONG)ARG1.val_Value.String);
  555.         rc = FALSE;
  556.         }
  557.     }
  558.     else
  559.         goto abort;
  560.     argc -= 2;
  561.     argv += 2;
  562.     }
  563.     res->val_Type = VTF_NUMBER;
  564.     res->val_Value.Number = rc;
  565. abort:
  566.     return(res);
  567. }
  568.  
  569. /*
  570.  * (type <value>)
  571.  */
  572. VALUE *
  573. cmd_type(LONG argc, VALUE *argv)
  574. {
  575.     setnumres(ARG1.val_Type);
  576.     return(&RES);
  577. }
  578.  
  579. /*
  580.  * some arithmetic commands
  581.  */
  582.  
  583. /* (+ 1 2) */
  584. VALUE *
  585. cmd_plus(LONG argc, VALUE *argv)
  586. {
  587.     setnumres(ARG1.val_Value.Number + ARG2.val_Value.Number);
  588.     return(&RES);
  589. }
  590.  
  591. /* (- 1 [2]) */
  592. VALUE *
  593. cmd_minus(LONG argc, VALUE *argv)
  594. {
  595.     if(argc == 1)
  596.     setnumres(-(ARG1.val_Value.Number));
  597.     else
  598.     setnumres(ARG1.val_Value.Number - ARG2.val_Value.Number);
  599.     return(&RES);
  600. }
  601.  
  602. /* (* 1 2) */
  603. VALUE *
  604. cmd_product(LONG argc, VALUE *argv)
  605. {
  606.     setnumres(ARG1.val_Value.Number * ARG2.val_Value.Number);
  607.     return(&RES);
  608. }
  609.  
  610. /* (/ 1 2) */
  611. VALUE *
  612. cmd_divide(LONG argv, VALUE *argv)
  613. {
  614.     setnumres(ARG1.val_Value.Number / ARG2.val_Value.Number);
  615.     return(&RES);
  616. }
  617.  
  618. /* (% 1 2) */
  619. VALUE *
  620. cmd_mod(LONG argc, VALUE *argv)
  621. {
  622.     setnumres(ARG1.val_Value.Number % ARG2.val_Value.Number);
  623.     return(&RES);
  624. }
  625.  
  626. /* (~ 1) */
  627. VALUE *
  628. cmd_b_not(LONG argc, VALUE *argv)
  629. {
  630.     setnumres(~ARG1.val_Value.Number);
  631.     return(&RES);
  632. }
  633.  
  634. /* (! 1) */
  635. VALUE *
  636. cmd_l_not(LONG argc, VALUE *argv)
  637. {
  638.     setnumres(!ARG1.val_Value.Number);
  639.     return(&RES);
  640. }
  641.  
  642. /* (| 1 2) */
  643. VALUE *
  644. cmd_b_or(LONG argc, VALUE *argv)
  645. {
  646.     setnumres(ARG1.val_Value.Number | ARG2.val_Value.Number);
  647.     return(&RES);
  648. }
  649.  
  650. /* (|| 1 2) */
  651. VALUE *
  652. cmd_l_or(LONG argc, VALUE *argv)
  653. {
  654.     setnumres(ARG1.val_Value.Number || ARG2.val_Value.Number);
  655.     return(&RES);
  656. }
  657.  
  658. /* (& 1 2) */
  659. VALUE *
  660. cmd_b_and(LONG argc, VALUE *argv)
  661. {
  662.     setnumres(ARG1.val_Value.Number & ARG2.val_Value.Number);
  663.     return(&RES);
  664. }
  665.  
  666. /* (&& 1 2) */
  667. VALUE *
  668. cmd_l_and(LONG argc, VALUE *argv)
  669. {
  670.     setnumres(ARG1.val_Value.Number && ARG2.val_Value.Number);
  671.     return(&RES);
  672. }
  673.  
  674. /* (^ 1 2) */
  675. VALUE *
  676. cmd_b_eor(LONG argc, VALUE *argv)
  677. {
  678.     setnumres(ARG1.val_Value.Number ^ ARG2.val_Value.Number);
  679.     return(&RES);
  680. }
  681.  
  682. /* (^^ 1 2) */
  683. VALUE *
  684. cmd_l_eor(LONG argc, VALUE *argv)
  685. {
  686.     if(ARG1.val_Value.Number)
  687.     {
  688.     if(ARG2.val_Value.Number)
  689.         setnumres(FALSE);
  690.     else
  691.         setnumres(TRUE);
  692.     }
  693.     else
  694.     setnumres(TRUE);
  695.     return(&RES);
  696. }
  697.  
  698. /* (<< 1 2) */
  699. VALUE *
  700. cmd_lshift(LONG argc, VALUE *argv)
  701. {
  702.     setnumres(ARG1.val_Value.Number << ARG2.val_Value.Number);
  703.     return(&RES);
  704. }
  705.  
  706. /* (>> 1 2) */
  707. VALUE *
  708. cmd_rshift(LONG argc, VALUE *argv)
  709. {
  710.     setnumres(ARG1.val_Value.Number >> ARG2.val_Value.Number);
  711.     return(&RES);
  712. }
  713.  
  714. /*
  715.  * (= `varname' value)
  716.  */
  717. VALUE *
  718. cmd_equals(LONG argc, VALUE *argv)
  719. {
  720.     if(TPLATE2(VTF_STRING, VTF_ANY))
  721.     {
  722.     LSYM *lsym;
  723.     GSYM *gsym;
  724.     BOOL rc = TRUE;
  725.     if(lsym = findlsym(ARG1.val_Value.String))
  726.     {
  727.         releasevalue(&lsym->ls_Sym.sym_Value);
  728.         if(!dupvalue(&lsym->ls_Sym.sym_Value, &ARG2))
  729.         rc = FALSE;
  730.     }
  731.     else if(gsym = findgsym(ARG1.val_Value.String))
  732.     {
  733.         releasevalue(&gsym->gs_Sym.sym_Value);
  734.         if(!dupvalue(&gsym->gs_Sym.sym_Value, &ARG2))
  735.         rc = FALSE;
  736.     }
  737.     else
  738.     {
  739.         if(!addlsym(ARG1.val_Value.String, STF_VARIABLE, &ARG2))
  740.         rc = FALSE;
  741.     }
  742.     if(!rc)
  743.         settitlefmt("error: can't set symbol %s", (LONG)ARG1.val_Value.String);
  744.     setnumres(rc);
  745.     }
  746.     return(&RES);
  747. }
  748.  
  749. /*
  750.  * comparison operators
  751.  */
  752.  
  753. /*
  754.  * (== `string1' `STRING2')
  755.  * (== 1 2)
  756.  */
  757. VALUE *
  758. cmd_equality(LONG argc, VALUE *argv)
  759. {
  760.     if((ARG1.val_Type == VTF_STRING) && (ARG2.val_Type == VTF_STRING))
  761.     setnumres(!stricmp(ARG1.val_Value.String, ARG2.val_Value.String));
  762.     else if((ARG1.val_Type == VTF_NUMBER) && (ARG2.val_Type == VTF_NUMBER))
  763.     setnumres(ARG1.val_Value.Number == ARG2.val_Value.Number);
  764.     else
  765.     settitle("syntax error: incorrect arguments to ==");
  766.     return(&RES);
  767. }
  768.  
  769. /*
  770.  * (!= `string1' `STRING2')
  771.  * (!= 1 2)
  772.  */
  773. VALUE *
  774. cmd_inequality(LONG argc, VALUE *argv)
  775. {
  776.     if((ARG1.val_Type == VTF_STRING) && (ARG2.val_Type == VTF_STRING))
  777.     setnumres(stricmp(ARG1.val_Value.String, ARG2.val_Value.String));
  778.     else if((ARG1.val_Type == VTF_NUMBER) && (ARG2.val_Type == VTF_NUMBER))
  779.     setnumres(ARG1.val_Value.String != ARG2.val_Value.String);
  780.     else
  781.     settitle("syntax error: incorrect arguments to !=");
  782.     return(&RES);
  783. }
  784.  
  785. /* (> 1 2) */
  786. VALUE *
  787. cmd_gtthan(LONG argc, VALUE *argv)
  788. {
  789.     setnumres(ARG1.val_Value.Number > ARG2.val_Value.Number);
  790.     return(&RES);
  791. }
  792.  
  793. /* (< 1 2) */
  794. VALUE *
  795. cmd_ltthan(LONG argc, VALUE *argv)
  796. {
  797.     setnumres(ARG1.val_Value.Number < ARG2.val_Value.Number);
  798.     return(&RES);
  799. }
  800.  
  801. /* (>= 1 2) */
  802. VALUE *
  803. cmd_gethan(LONG argc, VALUE *argv)
  804. {
  805.     setnumres(ARG1.val_Value.Number >= ARG2.val_Value.Number);
  806.     return(&RES);
  807. }
  808.  
  809. /* (<= 1 2) */
  810. VALUE *
  811. cmd_lethan(LONG argc, VALUE *argv)
  812. {
  813.     setnumres(ARG1.val_Value.Number <= ARG2.val_Value.Number);
  814.     return(&RES);
  815. }
  816.  
  817. /*
  818.  * (nop)
  819.  */
  820. VALUE *
  821. cmd_nop(LONG argc, VALUE *argv)
  822. {
  823.     setnumres(FALSE);
  824.     return(&RES);
  825. }
  826.